#include "Epoller.h"

#include <EventLoop.h>

Epoller::Epoller(EventLoop *loop, int epollFlag)
    : ownerLoop_(loop), epollfd_(epoll_create1(epollFlag)), events_(KInitEventListSize)
{
    assert(epollfd_ >= 0);
}

int Epoller::poll(int timeoutMs, std::vector<Channel *> &activeChannels)
{
    int ret = epoll_wait(epollfd_, events_.data(), events_.size(), timeoutMs);
    if (ret > 0)
    {
        std::cout << "epoller poll " << ret << " events" << std::endl;
        fillActiveChannels(ret, activeChannels);
    }
    else if (ret == events_.size())
    {
        std::cout << "epoller resize:" << events_.size() << std::endl;
        events_.resize(2 * events_.size());
    }
    else
    {
        std::cout << "epoll_wait error:" << strerror(errno) << std::endl;
    }
    return ret;
}

void Epoller::fillActiveChannels(int numEvents, std::vector<Channel *> &activeChannels)
{
    for (int i = 0; i < numEvents; ++i)
    {
        epoll_event event = events_[i];
        Channel *channel = static_cast<Channel *>(event.data.ptr);
        int fd = channel->fd();
        auto it = channelMap_.find(fd);
        std::cout << channel << std::endl;
        std::cout << it->second << std::endl;
        assert(it != channelMap_.end());
        assert(it->second == channel);
        channel->setRevent(event.events);
        activeChannels.push_back(channel);
    }
}

void Epoller::updateChannel(Channel *channel)
{
    ownerLoop_->assertInLoopThread();
    const int index = channel->index();
    std::cout << "fd = " << channel->fd()
              << " event = " << channel->event()
              << " index = " << index << std::endl;
    if (index == KNew || index == KDeleted)
    {
        int fd = channel->fd();
        if (index == KNew)
        {
            assert(channelMap_.find(fd) == channelMap_.end());
            channelMap_[fd] = channel;
        }
        else
        { // index = KDeleted
            assert(channelMap_.find(fd) != channelMap_.end() && channelMap_[fd] == channel);
        }
        channel->setIndex(KAdded);
        update(EPOLL_CTL_ADD, channel);
    }
    else // update existing channel with mod/del
    {
        int fd = channel->fd();
        (void)fd;
        assert(channelMap_.find(fd) != channelMap_.end() && channelMap_[fd] == channel);
        assert(index == KAdded);
        if (channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL, channel);
            channel->setIndex(KDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD, channel);
        }
    }
}

bool Epoller::hasChannel(Channel *channel)
{
    ownerLoop_->assertInLoopThread();
    auto it = channelMap_.find(channel->fd());
    return it != channelMap_.end() && it->second == channel;
}

void Epoller::removeChannel(Channel *channel)
{
    ownerLoop_->assertInLoopThread();
    int fd = channel->fd();
    std::cout << "removeChannel fd = " << fd << std::endl;
    assert(channelMap_.find(fd) != channelMap_.end() && channelMap_[fd] == channel);
    assert(channel->isNoneEvent());
    int index = channel->index();
    assert(index == KAdded || index == KDeleted);
    channelMap_.erase(fd);
    if (index == KAdded)
    {
        update(EPOLL_CTL_DEL, channel);
    }
    channel->setIndex(KDeleted);
}

bool Epoller::update(int operation, Channel *channel)
{
    epoll_event event;
    memset(&event, 0, sizeof(event));
    /*
      epoll_event的data是一个union,最大存储64bit
      note:所以这里只设置event.data.ptr即可,不可以fd和ptr同时设置,否则会被修改值,导致异常!!!
     */
    // event.data.fd = channel->fd();
    event.data.ptr = channel;
    event.events = channel->event();
    if (::epoll_ctl(epollfd_, operation, channel->fd(), &event) < 0)
    {
        std::cout << "epller update client " << channel->name() << " failed:" << strerror(errno) << std::endl;
        return false;
    }
    return true;
}
